/**
 * 
 */
package core.simple;

//import java.util.Set;

import core.IEnvironment;
import core.ICrossOver;
import core.IMutate;
import core.Problem;
import java.util.Random;

/**
 * @author AmmyLee
 *
 */
public abstract class SimpleEnvironment implements IEnvironment,ICrossOver,IMutate {

	Problem problem;
	double mutationParameter;
	double mutationProbability;
	double crossover;
	Random generator = new Random();

	
	Population p0,p_0;
	
	int sizeOfPopulation;
	int sizeOfArchieve;
	
	public SimpleEnvironment(){}

	public SimpleEnvironment(Problem problem,double mutationParameter,double mutationProbability,double cross){
		
		this.problem = problem;
		this.mutationParameter = mutationParameter;
		this.mutationProbability = mutationProbability;
		this.crossover = cross;
	}
	public void initPopulation(int genotypeLength, int sizeOfPopulation, int sizeOfArchieve){
		p0 = new Population(sizeOfPopulation);
		p_0 = new Population(sizeOfArchieve);
		this.sizeOfArchieve = sizeOfArchieve;
		this.sizeOfPopulation = sizeOfPopulation;
		
		double[] upperBound = new double[genotypeLength];
		double[] lowerBound = new double[genotypeLength];
		int i = 0;
		try {
			while(true) {
				upperBound[i] = problem.getUpperBound(i); 
				lowerBound[i] = problem.getLowerBound(i); 
				i++;
			}
		} catch (Exception e) {
			//Tu nic nie robimy
		}

		int indyviduals_counter = 0;
		
		while (indyviduals_counter < sizeOfPopulation){
			i = 0;
			double[] genotype = new double[genotypeLength];
			try {
				while(true) {
					genotype[i] = generator.nextDouble() * (upperBound[i] - lowerBound[i]) + lowerBound[i];
					i++;
				}
			} catch (Exception e) {
				//Tu nic nie robimy
			}
			this.p0.addGenotype(genotype).results = problem.calculate(genotype);
			indyviduals_counter++;
		}
	}


	public double[] mutate(double[] g){
		double rnd, delta1, delta2, mut_pow, deltaq;
		double y, yl, yu, val, xy;
		double [] genotype = new double[g.length];
		
		int var;
		try {
			var = 0;
			while (true){
				genotype[var] = g[var];
				var++;
			}
		} catch (Exception e){
			//la!
		}
		

		try {
			var = 0;
			while (true) {
				if (this.generator.nextDouble() < this.mutationProbability) {
					y = genotype[var];
					yl = problem.getLowerBound(var);
					yu = problem.getUpperBound(var);
					delta1 = (y - yl) / (yu - yl);
					delta2 = (yu - y) / (yu - yl);
					rnd = this.generator.nextDouble();
					mut_pow = 1.0 / (this.mutationParameter + 1.0);
					if (rnd <= 0.5) {
						xy = 1.0 - delta1;
						val = 2.0
								* rnd
								+ (1.0 - 2.0 * rnd)
								* (Math.pow(xy, (this.mutationParameter + 1.0)));
						deltaq = java.lang.Math.pow(val, mut_pow) - 1.0;
					} else {
						xy = 1.0 - delta2;
						val = 2.0
								* (1.0 - rnd)
								+ 2.0
								* (rnd - 0.5)
								* (java.lang.Math.pow(xy,
										(this.mutationParameter + 1.0)));
						deltaq = 1.0 - (java.lang.Math.pow(val, mut_pow));
					}
					y = y + deltaq * (yu - yl);
					if (y < yl)
						y = yl;
					if (y > yu)
						y = yu;
					genotype[var] = y;
				}
				var++;
			}
		} catch (ArrayIndexOutOfBoundsException e) {
			// tu nic nie robimy
		}
		return genotype;
	}

	public double[][] crossOver(double[] first, double[] second){
		double [][]tmp = new double[2][first.length];
		double bq,yl,yu;
		double u;
		int i = 0;
		try {
			while(true){
		
				u = generator.nextDouble();
		        if (u <= 0.5)
		            bq = Math.pow((2.0 * u), (1.0 / (this.crossover + 1.0)));
		        else
		            bq = 1.0 / Math.pow(((2.0 * (1.0 - u))), (1.0 / (this.crossover + 1.0)));
	            tmp[0][i] = 0.5 * (((1.0 + bq) * first[i]) + (1.0 - bq) * second[i]);
	            tmp[1][i] = 0.5 * (((1.0 - bq) * first[i]) + (1.0 + bq) * second[i]);
				
	            yl = problem.getLowerBound(i);
				yu = problem.getUpperBound(i);
				bq = (yu - yl)*Math.abs(u)*0.5+yl;
				
				if (tmp[0][i]>yu)
					tmp[0][i] = bq;
				else if (tmp[0][i]<yl)
					tmp[0][i] = bq;
				
				if (tmp[1][i]>yu)
					tmp[1][i] = bq;
				else if (tmp[1][i]<yl)
					tmp[1][i] = bq;
	            i++;
			}
		}catch (Exception e){

		}   
        return tmp;
	}
	public void normalize(double [] genotype){
		
	}

}
